// 在传统的面向对象语言中，给对象添加功能常常使用继承的方式，但是继承的方式并不灵活， 
// 还会带来许多问题:一方面会导致超类和子类之间存在强耦合性，当超类改变时，
// 子类也会随之 改变;另一方面，继承这种功能复用方式通常被称为“白箱复用”，
// “白箱”是相对可见性而言的， 在继承方式中，超类的内部细节是对子类可见的，
// 继承常常被认为破坏了封装性。装饰者模式能够在不改变对象自身的基础上，
// 在程序运行期间给对象动态地添加职责。跟继承相比，装饰者是一种更轻便灵活的做法，
// 这是一种“即用即付”的方式

// 假设我们在编写一个飞机大战的游戏， 随着经验值的增加， 我们操作的飞机对象可以升级成更厉害的飞机， 一开始这些飞机只能发射普通的子弹， 升到第二级时可以发射导弹， 升到第三级时可以发射原子弹。

// 代码实现(使用装饰者模式)

var plane = {
    fire: function() {
        console.log('发射普通子弹');
    }
}
var missileDecorator = function() {
    console.log('发射导弹');
}
var atomDecorator = function() {
    console.log('发射原子弹');
}
var fire1 = plane.fire;
plane.fire = function() {
    fire1();
    missileDecorator();
}
var fire2 = plane.fire;
plane.fire = function() {
    fire2();
    atomDecorator();
}
plane.fire();
// 分别输出: 发射普通子弹、发射导弹、发射原子弹